﻿@using System.Collections.Concurrent
@implements IDisposable

<Console Items="@Messages" Height="126" ShowAutoScroll="true" OnClear="@OnClear" />

@code {
    private ConcurrentQueue<ConsoleMessageItem> Messages { get; set; } = new();

    private readonly AutoResetEvent _locker = new(true);

    private CancellationTokenSource? CancelTokenSource { get; set; }

    /// <summary>
    /// OnAfterRender
    /// </summary>
    /// <param name="firstRender"></param>
    protected override void OnAfterRender(bool firstRender)
    {
        if (firstRender)
        {
            Task.Run(async () =>
            {
                CancelTokenSource ??= new();
                while (CancelTokenSource != null && !CancelTokenSource.IsCancellationRequested)
                {
                    _locker.WaitOne();
                    Messages.Enqueue(new ConsoleMessageItem { Message = $"{DateTimeOffset.Now}: Dispatch Message" });

                    if (Messages.Count > 8)
                    {
                        Messages.TryDequeue(out var _);
                    }

                    await InvokeAsync(StateHasChanged);
                    _locker.Set();

                    try
                    {
                        if (CancelTokenSource != null)
                        {
                            await Task.Delay(2000, CancelTokenSource.Token);
                        }
                    }
                    catch { }
                }
            });
        }
    }

    /// <summary>
    /// OnClear
    /// </summary>
    private void OnClear()
    {
        _locker.WaitOne();
        while (!Messages.IsEmpty)
        {
            Messages.TryDequeue(out var _);
        }
        _locker.Set();
    }

    /// <summary>
    /// Dispose
    /// </summary>
    /// <param name="disposing"></param>
    private void Dispose(bool disposing)
    {
        if (disposing && CancelTokenSource != null)
        {
            CancelTokenSource.Cancel();
            CancelTokenSource.Dispose();
            CancelTokenSource = null;
        }
    }

    /// <summary>
    /// Dispose
    /// </summary>
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}
